package com.mini.grpc.client;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

/**
 * CallOptions包含一组可选参数，用于控制RPC调用的行为。
 */
public final class CallOptions {
    
    /**
     * 默认的调用选项
     */
    public static final CallOptions DEFAULT = new CallOptions();
    
    private Executor executor;
    private Long deadlineNanoTime;
    private Map<CallOption<?>, Object> customOptions;
    private List<ClientInterceptor> interceptors;
    
    /**
     * 构造一个默认的CallOptions
     */
    private CallOptions() {
        this(null, null, Collections.emptyMap(), Collections.emptyList());
    }
    
    /**
     * 构造一个CallOptions
     *
     * @param executor 执行器
     * @param deadlineNanoTime 截止时间（纳秒）
     * @param customOptions 自定义选项
     * @param interceptors 拦截器列表
     */
    private CallOptions(
            Executor executor,
            Long deadlineNanoTime,
            Map<CallOption<?>, Object> customOptions,
            List<ClientInterceptor> interceptors) {
        this.executor = executor;
        this.deadlineNanoTime = deadlineNanoTime;
        this.customOptions = customOptions;
        this.interceptors = interceptors;
    }
    
    /**
     * 创建一个带有执行器的新CallOptions
     *
     * @param executor 执行器
     * @return 新的CallOptions
     */
    public CallOptions withExecutor(Executor executor) {
        return new CallOptions(executor, deadlineNanoTime, customOptions, interceptors);
    }
    
    /**
     * 获取执行器
     *
     * @return 执行器
     */
    public Executor getExecutor() {
        return executor;
    }
    
    /**
     * 创建一个带有截止时间的新CallOptions
     *
     * @param duration 持续时间
     * @param unit 时间单位
     * @return 新的CallOptions
     */
    public CallOptions withDeadlineAfter(long duration, TimeUnit unit) {
        return withDeadlineNanoTime(System.nanoTime() + unit.toNanos(duration));
    }
    
    /**
     * 创建一个带有截止时间的新CallOptions
     *
     * @param deadlineNanoTime 截止时间（纳秒）
     * @return 新的CallOptions
     */
    public CallOptions withDeadlineNanoTime(long deadlineNanoTime) {
        return new CallOptions(executor, deadlineNanoTime, customOptions, interceptors);
    }
    
    /**
     * 获取截止时间（纳秒）
     *
     * @return 截止时间（纳秒）
     */
    public Long getDeadlineNanoTime() {
        return deadlineNanoTime;
    }
    
    /**
     * 创建一个带有自定义选项的新CallOptions
     *
     * @param option 选项键
     * @param value 选项值
     * @param <T> 选项值类型
     * @return 新的CallOptions
     */
    public <T> CallOptions withOption(CallOption<T> option, T value) {
        Map<CallOption<?>, Object> newCustomOptions = new HashMap<>(customOptions);
        newCustomOptions.put(option, value);
        return new CallOptions(executor, deadlineNanoTime, newCustomOptions, interceptors);
    }
    
    /**
     * 获取自定义选项的值
     *
     * @param option 选项键
     * @param <T> 选项值类型
     * @return 选项值，如果不存在则返回null
     */
    @SuppressWarnings("unchecked")
    public <T> T getOption(CallOption<T> option) {
        return (T) customOptions.get(option);
    }
    
    /**
     * 创建一个带有拦截器的新CallOptions
     *
     * @param interceptors 拦截器数组
     * @return 新的CallOptions
     */
    public CallOptions withInterceptors(ClientInterceptor... interceptors) {
        if (interceptors.length == 0) {
            return this;
        }
        
        List<ClientInterceptor> newInterceptors = new ArrayList<>(this.interceptors);
        newInterceptors.addAll(Arrays.asList(interceptors));
        return new CallOptions(executor, deadlineNanoTime, customOptions, newInterceptors);
    }
    
    /**
     * 获取拦截器列表
     *
     * @return 拦截器列表
     */
    public List<ClientInterceptor> getInterceptors() {
        return Collections.unmodifiableList(interceptors);
    }
    
    /**
     * 表示一个自定义调用选项的键
     *
     * @param <T> 选项值类型
     */
    public static final class CallOption<T> {
        private final String name;
        
        private CallOption(String name) {
            this.name = name;
        }
        
        /**
         * 创建一个新的调用选项键
         *
         * @param name 选项名称
         * @param <T> 选项值类型
         * @return 新的调用选项键
         */
        public static <T> CallOption<T> create(String name) {
            return new CallOption<>(name);
        }
        
        @Override
        public String toString() {
            return name;
        }
        
        @Override
        public int hashCode() {
            return name.hashCode();
        }
        
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }
            CallOption<?> that = (CallOption<?>) obj;
            return name.equals(that.name);
        }
    }
} 